package common

import chisel3._
import chisel3.util.{log2Ceil, log2Up}
import common.Constants._
import top.Settings

object Constants extends
  ScalarOpConstants with
  RISCVConstants with
  MyCoreParameter with
  MemoryOpConstants with
  PrivilegedConstants with
  CacheConst
{}

trait PrivilegedConstants{
  val START_ADDR = "h80000000".U
}

trait CacheConst {
  val TotalSize = 4 // KB
  val Ways = 4
  val BlockBytes = 16 // byte, 16B
  val Sets = TotalSize * 1024 / BlockBytes / Ways //Sets = 64

  val BlockBits = BlockBytes << 3
  val OffsetBits = log2Up(BlockBytes)
  val IndexBits = log2Up(Sets)

  val WordBytes = XLEN / 8
  val nWords = BlockBits / XLEN
  val wordOffset = log2Ceil(nWords)
  val byteOffsetBits = log2Ceil(WordBytes)
  val TagBits = AddrBits - OffsetBits - IndexBits



  //def getMetaIdx(addr: UInt) = addr.asTypeOf(addrBundle).index

}
trait MyCoreParameter {
  // General Parameter for MyCore
  val XLEN = if (Settings.get("IsRV32")) 32 else 64
  //val XLEN = 64
  val DataBits = XLEN
  val DataBytes = DataBits / 8
  val AddrBits = 32
  val IBufSize = 4
  val use_bypass = true
  val FPGA = if(Settings.get("FPGAPlatform")) true else false
  val hasRVM = if(Settings.get("HasRVM")) true else false
}

  trait RISCVConstants {
    val Width = UInt(32.W)

    // abstract out instruction decode magic numbers
    val RD_MSB = 11
    val RD_LSB = 7
    val RS1_MSB = 19
    val RS1_LSB = 15
    val RS2_MSB = 24
    val RS2_LSB = 20

    val CSR_ADDR_MSB = 31
    val CSR_ADDR_LSB = 20
    val BUBBLE  = 0x4033.U(32.W)
    val X0 = 0.U
  }

trait ScalarOpConstants
{
  //************************************
  // Control Signals

  val Y      = true.B
  val N      = false.B

  // PC Select Signal
  val PC_4   = 0.asUInt(3.W)  // PC + 4
  val PC_BR  = 1.asUInt(3.W)  // branch_target
  val PC_J   = 2.asUInt(3.W)  // jump_target
  val PC_JR  = 3.asUInt(3.W)  // jump_reg_target
  val PC_EXC = 4.asUInt(3.W)  // exception

  // Branch Type
  val BR_N   = 0.asUInt(4.W)  // Next
  val BR_NE  = 1.asUInt(4.W)  // Branch on NotEqual
  val BR_EQ  = 2.asUInt(4.W)  // Branch on Equal
  val BR_GE  = 3.asUInt(4.W)  // Branch on Greater/Equal
  val BR_GEU = 4.asUInt(4.W)  // Branch on Greater/Equal Unsigned
  val BR_LT  = 5.asUInt(4.W)  // Branch on Less Than
  val BR_LTU = 6.asUInt(4.W)  // Branch on Less Than Unsigned
  val BR_J   = 7.asUInt(4.W)  // Jump
  val BR_JR  = 8.asUInt(4.W)  // Jump Register
  val BR_CALL  = 9.asUInt(4.W) 
  val BR_RET  = 10.asUInt(4.W)

  // RS1 Operand Select Signal
  val OP1_RS1 = 0.asUInt(2.W) // Register Source #1
  val OP1_IMU = 1.asUInt(2.W) // immediate, U-type
  val OP1_IMZ = 2.asUInt(2.W) // Zero-extended rs1 field of inst, for CSRI instructions
  val OP1_IMJ = 3.asUInt(2.W)
  val OP1_X   = 0.asUInt(2.W)

  // RS2 Operand Select Signal
  val OP2_RS2 = 0.asUInt(3.W) // Register Source #2
  val OP2_IMI = 1.asUInt(3.W) // immediate, I-type
  val OP2_IMS = 2.asUInt(3.W) // immediate, S-type
  val OP2_IMB = 3.asUInt(3.W)
  val OP2_PC  = 4.asUInt(3.W) // PC
  val OP2_X   = 0.asUInt(3.W)

  // regfile read enable
  val OEN_0 = false.B
  val OEN_1 = true.B

  // Register File Write Enable Signal
  val REN_0   = false.B
  val REN_1   = true.B
  val REN_X   = false.B

  // FU TYPE
  val FU_X = 0.asUInt(2.W)
  val FU_ALU = 0.asUInt(2.W)
  val FU_MDU = 1.asUInt(2.W)
  val FU_LSU = 2.asUInt(2.W)

  val fuOpType = 4
  // ALU Operation Signal
  val ALU_X   = 0.asUInt(fuOpType.W)
  val ALU_ADD = 0.asUInt(fuOpType.W)
  val ALU_SUB = 1.asUInt(fuOpType.W)
  val ALU_SLL = 2.asUInt(fuOpType.W)
  val ALU_SRL = 3.asUInt(fuOpType.W)
  val ALU_SRA = 4.asUInt(fuOpType.W)
  val ALU_AND = 5.asUInt(fuOpType.W)
  val ALU_OR  = 6.asUInt(fuOpType.W)
  val ALU_XOR = 7.asUInt(fuOpType.W)
  val ALU_SLT = 8.asUInt(fuOpType.W)
  val ALU_SLTU= 9.asUInt(fuOpType.W)
  val ALU_COPY1= 10.asUInt(fuOpType.W)
  val ALU_ADDW = 11.asUInt(fuOpType.W)
  val ALU_SUBW = 12.asUInt(fuOpType.W)
  val ALU_SLLW = 13.asUInt(fuOpType.W)
  val ALU_SRLW = 14.asUInt(fuOpType.W)
  val ALU_SRAW = 15.asUInt(fuOpType.W)

  
  // MDU Operation Signal
  val MDU_X = 0.asUInt(fuOpType.W)
  val MDU_MUL = 0.asUInt(fuOpType.W)
  val MDU_MULH = 1.asUInt(fuOpType.W)
  val MDU_MULHU = 2.asUInt(fuOpType.W)
  val MDU_MULHSU = 3.asUInt(fuOpType.W)
  val MDU_MULW = 4.asUInt(fuOpType.W)

  val MDU_DIV = 5.asUInt(fuOpType.W)
  val MDU_DIVU = 6.asUInt(fuOpType.W)
  val MDU_REM = 7.asUInt(fuOpType.W)
  val MDU_REMU = 8.asUInt(fuOpType.W)

  val MDU_DIVW = 9.asUInt(fuOpType.W)
  val MDU_DIVUW = 10.asUInt(fuOpType.W)
  val MDU_REMW = 11.asUInt(fuOpType.W)
  val MDU_REMUW = 12.asUInt(fuOpType.W)

  // LSU Operation Signal
  val LSU_X = 0.asUInt(3.W)
  val LSU_B = 1.asUInt(3.W)
  val LSU_H= 2.asUInt(3.W)
  val LSU_W = 3.asUInt(3.W)
  val LSU_D = 4.asUInt(3.W)
  val LSU_BU = 5.asUInt(3.W)
  val LSU_HU = 6.asUInt(3.W)
  val LSU_WU = 7.asUInt(3.W)

  // Writeback Select Signal
  val WB_X    = 0.asUInt(2.W)
  val WB_EXE  = 0.asUInt(2.W)
  //val WB_LSU  = 1.asUInt(2.W)
  val WB_PC4  = 1.asUInt(2.W)
  val WB_CSR  = 2.asUInt(2.W)

  // Memory Function Type (Read,Write,Fence) Signal
  val MWR_R   = 0.asUInt(2.W)
  val MWR_W   = 1.asUInt(2.W)
  val MWR_F   = 2.asUInt(2.W)
  val MWR_X   = 0.asUInt(2.W)

  // Memory Enable Signal
  val MEM_0   = false.B
  val MEM_1   = true.B
  val MEM_X   = false.B

  // Memory Mask Type Signal
  val MSK_B   = 0.asUInt(3.W)
  val MSK_BU  = 1.asUInt(3.W)
  val MSK_H   = 2.asUInt(3.W)
  val MSK_HU  = 3.asUInt(3.W)
  val MSK_W   = 4.asUInt(3.W)
  val MSK_X   = 4.asUInt(3.W)

  // Cache Flushes & Sync Primitives
  val M_N      = 0.asUInt(3.W)
  val M_SI     = 1.asUInt(3.W)   // synch instruction stream
  val M_SD     = 2.asUInt(3.W)   // synch data stream
  val M_FA     = 3.asUInt(3.W)   // flush all caches
  val M_FD     = 4.asUInt(3.W)   // flush data cache

  // Memory Functions (read, write, fence)
  val MT_READ  = 0.asUInt(2.W)
  val MT_WRITE = 1.asUInt(2.W)
  val MT_FENCE = 2.asUInt(2.W)

}
trait MemoryOpConstants
{
  val MT_X  = 0.asUInt(3.W)
  val MT_B  = 1.asUInt(3.W)
  val MT_H  = 2.asUInt(3.W)
  val MT_W  = 3.asUInt(3.W)
  val MT_D  = 4.asUInt(3.W)
  val MT_BU = 5.asUInt(3.W)
  val MT_HU = 6.asUInt(3.W)
  val MT_WU = 7.asUInt(3.W)

  val M_X   = "b0".asUInt(1.W)
  val M_XRD = "b0".asUInt(1.W) // int load
  val M_XWR = "b1".asUInt(1.W) // int store

  val IPORT = 0.U
  val DPORT = 1.U

}
// object Causes {
//   // Exception
//   val misaligned_fetch = 0x0  // Instruction address misaligned
//   val fetch_access = 0x1  //  Instruction access fault
//   val illegal_instruction = 0x2 // Illegal instruction
//   val breakpoint = 0x3  // Breakpoint
//   val misaligned_load = 0x4 // Load address misaligned
//   val load_access = 0x5 // Load access fault
//   val misaligned_store = 0x6  // Store/AMO address misaligned
//   val store_access = 0x7  // Store/AMO access fault
//   val u_ecall = 0x8.U // Environment call from U-mode
//   val s_ecall = 0x9.U // Environment call from S-mode
//   val m_ecall = 0xb // Environment call from M-mode
//   // Interrupt
//   val interrupt = 1.U << (XLEN - 1)
//   val user_software_interrupt = interrupt | 0x0.U
//   val supervisor_software_interrupt = interrupt | 0x1.U
//   val machine_software_interrupt = interrupt | 0x3.U
//   val machine_timer_interrupt = interrupt | 0x7.U
// }